﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;

namespace Evan.Security
{
    /// <summary>  
    /// Web请求安全检查：防止跨站点脚本,Sql注入等攻击  
    /// 检查数据包括:  
    /// 1.Cookie  
    /// 2.当前页面地址  
    /// 3.ReferrerUrl  
    /// 4.Post数据  
    /// 5.Get数据  
    /// </summary> 
    public class SafeCheck
    {
        #region 执行安全检查

        /// <summary>  
        /// 执行安全检查  
        /// </summary>  
        public static bool Procress()
        {
            //如果配置了不检查 , 那么就不要检查了
            try
            {
                if (Evan.Common.CommFun.GetAppSetting("SecurityLevel").ToLower() == "low")
                {
                    return true;
                }
            }
            catch
            {
                throw new Exception("web.config中的appSettings节点未配置SecurityLevel属性");
            }

            if (RawUrl())
            {
                return false;
            }

            if (CookieData())
            {
                return false;
            }

            if (HttpContext.Current.Request.UrlReferrer != null)
            {
                if (Referer())
                {
                    return false;
                }
            }

            if (HttpContext.Current.Request.RequestType.ToUpper() == "POST")
            {
                if (PostData())
                {
                    return false;
                }
            }
            if (HttpContext.Current.Request.RequestType.ToUpper() == "GET")
            {
                if (GetData())
                {
                    return false;
                }
            }
            if (HeaderData())
            {
                return false;
            }
            return true;
        }

        #endregion

        #region 安全检查正则

        /// <summary>  
        /// 安全检查正则  
        /// </summary>  
        private const string StrRegex = @"<[^>]+?style=[\w]+?:expression\(|\b(alert|confirm|prompt)\b|^\+/v(8|9)|<[^>]*?=[^>]*?&#[^>]*?>|\b(and|or)\b.{1,6}?(=|>|<|\bin\b|\blike\b)|/\*.+?\*/|<\s*script\b|\bEXEC\b|UNION.+?SELECT|UPDATE.+?SET|INSERT\s+INTO.+?VALUES|(SELECT|DELETE).+?FROM|(CREATE|ALTER|DROP|TRUNCATE)\s+(TABLE|DATABASE)";

        //private const string StrRegex = @"<[^>]+?style=[\w]+?:expression\(|\b(alert|confirm|prompt)\b|^\+/v(8|9)|<[^>]*?=[^>]*?&#[^>]*?>|\b(and|or)\b.{1,6}?(=|>|<|\bin\b|\blike\b)|/\*.+?\*/|<\s*script\b|<\s*img\b|\bEXEC\b|UNION.+?SELECT|UPDATE.+?SET|INSERT\s+INTO.+?VALUES|(SELECT|DELETE).+?FROM|(CREATE|ALTER|DROP|TRUNCATE)\s+(TABLE|DATABASE)";


        #endregion

        #region 检查Header数据

        /// <summary>  
        /// 检查Header数据 
        /// </summary>  
        /// <returns></returns>  
        private static bool HeaderData()
        {
            bool result = false;
            string[] ExCludeSafePara = Evan.Common.CommFun.GetAppSetting("ExCludeSafePara").Split(',');
            for (int i = 0; i < HttpContext.Current.Request.Headers.Count; i++)
            {
                if (!ExCludeSafePara.Contains(HttpContext.Current.Request.Headers.Keys[i].ToLower()))
                {
                    result = CheckData(HttpContext.Current.Request.Headers[i].ToLower());
                    if (result)
                    {
                        break;
                    }
                }
            }
            return result;
        }

        #endregion

        #region 检查Post数据

        /// <summary>  
        /// 检查Post数据  
        /// </summary>  
        /// <returns></returns>  
        private static bool PostData()
        {
            bool result = false;

            for (int i = 0; i < HttpContext.Current.Request.Form.Count; i++)
            {
                result = CheckData(HttpContext.Current.Request.Form[i]);
                if (result)
                {
                    break;
                }
            }
            return result;
        }

        #endregion

        #region 检查Get数据

        /// <summary>  
        /// 检查Get数据  
        /// </summary>  
        /// <returns></returns>  
        private static bool GetData()
        {
            bool result = false;

            for (int i = 0; i < HttpContext.Current.Request.QueryString.Count; i++)
            {
                result = CheckData(HttpContext.Current.Request.QueryString[i]);
                if (result)
                {
                    break;
                }
            }
            return result;
        }

        #endregion

        #region 检查Cookie数据

        /// <summary>  
        /// 检查Cookie数据  
        /// </summary>  
        /// <returns></returns>  
        private static bool CookieData()
        {
            bool result = false;
            for (int i = 0; i < HttpContext.Current.Request.Cookies.Count; i++)
            {
                result = CheckData(HttpContext.Current.Request.Cookies[i].Value.ToLower());
                if (result)
                {
                    break;
                }
            }
            return result;
        }

        #endregion

        #region 检查Referer

        /// <summary>  
        /// 检查Referer  
        /// </summary>  
        /// <returns></returns>  
        private static bool Referer()
        {
            return CheckData(HttpContext.Current.Request.UrlReferrer.ToString());
        }

        #endregion

        #region 检查当前请求路径

        /// <summary>  
        /// 检查当前请求路径  
        /// </summary>  
        /// <returns></returns>  
        private static bool RawUrl()
        {
            return CheckData(HttpContext.Current.Request.RawUrl);
        }

        #endregion

        #region 正则匹配

        /// <summary>  
        /// 正则匹配  
        /// </summary>  
        /// <param name="inputData"></param>  
        /// <returns></returns>  
        private static bool CheckData(string inputData)
        {
            inputData = HttpUtility.UrlDecode(inputData);
            var strRawUrl = HttpContext.Current.Request.RawUrl.ToLower();

            return Regex.IsMatch(inputData, StrRegex, RegexOptions.IgnoreCase);

        }

        #endregion  
    }
}
